package com.yuqiaotech.dbpro.filter.transaction;

import java.sql.Savepoint;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;


/**
 * 增加对事务监控的支持
 * 
 * @author Administrator
 *
 */
public class TransactionInfo {
	
	// 递增序列
	private long transactionId;
	private long createTime;
	private long commitTime;
	private long lastRollbackTime;
	private List<StatementInfo> statementInfos;
	private Map<Savepoint, SavepointInfo> savepointMap;
	
	public TransactionInfo() {
		
		// 注意：两个成员变量实现都是Linked
		statementInfos = new LinkedList<StatementInfo>();
		savepointMap = new LinkedHashMap<Savepoint, SavepointInfo>();
	}

	public long getCreateTime() {
		return createTime;
	}

	public void setCreateTime(long createTime) {
		this.createTime = createTime;
	}
	
	public long getCommitTime() {
		return commitTime;
	}

	public void setCommitTime(long commitTime) {
		this.commitTime = commitTime;
	}

	public long getLastRollbackTime() {
		return lastRollbackTime;
	}

	public void setLastRollbackTime(long lastRollbackTime) {
		this.lastRollbackTime = lastRollbackTime;
	}

	public Map<Savepoint, SavepointInfo> getSavepointMap() {
		return savepointMap;
	}

	public void addSavepoint(Savepoint savepoint) {
		if (null == savepoint) return;
		
		SavepointInfo info = new SavepointInfo();
		info.setCreateTime(System.currentTimeMillis());
		info.setPosition(null == statementInfos ? -1 : statementInfos.size() - 1);
		savepointMap.put(savepoint, info);
	}
	
	public boolean removeSavepoint(Savepoint savepoint) {
		
		SavepointInfo info = savepointMap.remove(savepoint);
		return null == info ? false : true;
		
	}
	
	public void rollback(Savepoint savepoint) {
		if (null == savepoint) return;
		
		SavepointInfo info = savepointMap.get(savepoint);
		Iterator<StatementInfo> statementItor = statementInfos.iterator();
		int beginRemoveStatments = info.getPosition();
		int i = 0;
		long now = System.currentTimeMillis();
		while (statementItor.hasNext()) {
			// 遍历下个元素
			StatementInfo statementInfo = statementItor.next();
			if (i > beginRemoveStatments) {
				statementInfo.status = StatementInfo.ROLLBACKED;
				statementInfo.setRollbackTime(now);
				statementItor.remove();
			}
			i ++;
		}
		
		// 删除无效的savepoint
		boolean beginDeleteSavepoint = false;
		Iterator<Map.Entry<Savepoint, SavepointInfo>> savepointItor = savepointMap.entrySet().iterator();
		while (savepointItor.hasNext()) {
			Map.Entry<Savepoint, SavepointInfo> entry = savepointItor.next();
			if (beginDeleteSavepoint) {
				savepointItor.remove();
			}
			
			// 该savepoint之后的savepoint都需要删除掉
			if (savepoint == entry.getKey()) {
				beginDeleteSavepoint = true;
			}
		}
	}
	
	public void rollback() {
		rollbackOrCommit(StatementInfo.ROLLBACKED);
	}
	
	public void commit() {
		rollbackOrCommit(StatementInfo.COMMITTED);
	}
	
	private void rollbackOrCommit(int status) {
		long now = System.currentTimeMillis();
		for(StatementInfo info : statementInfos) {
			info.status = status;
			if (status == StatementInfo.ROLLBACKED) {
				info.setRollbackTime(now);
			} else if (status == StatementInfo.COMMITTED) {
				info.setCommitTime(now);
			}
		}
		// 清除无效的数据
		statementInfos.clear();
		savepointMap.clear();
	}
	
	public void addStatementInfo(StatementInfo info) {
		if (null == info) return;
		
		statementInfos.add(info);
	}

	public List<StatementInfo> getStatementInfos() {
		return new ArrayList<StatementInfo>(statementInfos);
	}
	
	public long getTransactionId() {
		return transactionId;
	}

	public void setTransactionId(long transactionId) {
		this.transactionId = transactionId;
	}



	/**
	 * Savepoint信息，可以扩充
	 * 
	 * @author Administrator
	 *
	 */
	private class SavepointInfo {
		
		// 该Savepoint之前所执行的SQL的个数
		private int position;
		private long createTime;
		
		public long getCreateTime() {
			return createTime;
		}
		
		public void setCreateTime(long createTime) {
			this.createTime = createTime;
		}
		
		public int getPosition() {
			return position;
		}
		
		public void setPosition(int position) {
			this.position = position;
		}
	}

}
